#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;

// 矩阵结构体，用于表示状态转移矩阵
struct Matrix {
  int r, c;
  int d[3][3];

  // 初始化矩阵为指定大小，并填充为无穷大
  void init(int rows, int cols) {
    r = rows;
    c = cols;
    memset(d, 0x3f, sizeof(d));
  }
};

Matrix seg[N << 2]; // 线段树存储矩阵
Matrix res;         // 查询结果矩阵

char s[3][N]; // 存储网格数据

// 矩阵乘法：计算两个矩阵的最小路径和
Matrix operator*(const Matrix &m1, const Matrix &m2) {
  Matrix m;
  m.init(m1.r, m2.c);

  for (int i = 0; i < m1.r; i++) {
    for (int j = 0; j < m2.c; j++) {
      for (int k = 0; k < m1.c; k++) {
        // 计算最小路径和
        m.d[i][j] = min(m.d[i][j], m1.d[i][k] + m2.d[k][j]);
      }
    }
  }
  return m;
}

// 检查单元格是否可通行（不是障碍物）
bool canPass(char cell) { return cell == '.'; }

// 根据三个连续的列创建状态转移矩阵
Matrix getMat(char c1, char c2, char c3) {
  Matrix m;
  m.init(3, 3);

  // 定义状态转移规则：
  // 状态0: 从第一行开始
  // 状态1: 从第二行开始
  // 状态2: 从第三行开始

  // 从状态0到状态0: 只走第一行
  m.d[0][0] = canPass(c1) ? 1 : INF;
  // 从状态0到状态1: 走第一行和第二行
  m.d[0][1] = (canPass(c1) && canPass(c2)) ? 2 : INF;
  // 从状态0到状态2: 走所有三行
  m.d[0][2] = (canPass(c1) && canPass(c2) && canPass(c3)) ? 3 : INF;

  // 从状态1到状态0: 走第二行和第一行
  m.d[1][0] = (canPass(c1) && canPass(c2)) ? 2 : INF;
  // 从状态1到状态1: 只走第二行
  m.d[1][1] = canPass(c2) ? 1 : INF;
  // 从状态1到状态2: 走第二行和第三行
  m.d[1][2] = (canPass(c2) && canPass(c3)) ? 2 : INF;

  // 从状态2到状态0: 走所有三行
  m.d[2][0] = (canPass(c1) && canPass(c2) && canPass(c3)) ? 3 : INF;
  // 从状态2到状态1: 走第三行和第二行
  m.d[2][1] = (canPass(c2) && canPass(c3)) ? 2 : INF;
  // 从状态2到状态2: 只走第三行
  m.d[2][2] = canPass(c3) ? 1 : INF;

  return m;
}

#define ls (p << 1)
#define rs (p << 1 | 1)

// 更新线段树节点（合并左右子树）
void pushup(int p) { seg[p] = seg[ls] * seg[rs]; }

// 构建线段树
void build(int p, int l, int r) {
  if (l == r) {
    // 叶子节点：为当前列创建转移矩阵
    seg[p] = getMat(s[0][l], s[1][l], s[2][l]);
  } else {
    int mid = (l + r) >> 1;
    build(ls, l, mid);
    build(rs, mid + 1, r);
    pushup(p);
  }
}

// 更新线段树中的特定位置
void update(int p, int l, int r, int pos) {
  if (l == r) {
    // 更新叶子节点
    seg[p] = getMat(s[0][pos], s[1][pos], s[2][pos]);
  } else {
    int mid = (l + r) >> 1;
    if (pos <= mid) {
      update(ls, l, mid, pos);
    } else {
      update(rs, mid + 1, r, pos);
    }
    pushup(p);
  }
}

// 切换单元格状态（障碍物 ↔ 可通行）
void toggle(int row, int col) {
  if (s[row][col] == '.') {
    s[row][col] = '#';
  } else {
    s[row][col] = '.';
  }
}

int main() {
  int n, q; // 网格大小和查询次数
  // 读取输入
  scanf("%d", &n);
  for (int i = 0; i < 3; i++) {
    scanf("%s", s[i] + 1);
  }

  // 构建线段树
  build(1, 1, n);

  // 处理查询
  scanf("%d", &q);
  int x, y;

  while (q--) {
    scanf("%d %d", &x, &y);
    x--; // 转换为0-based索引

    // 切换单元格状态
    toggle(x, y);

    // 更新线段树
    update(1, 1, n, y);

    // 初始化结果矩阵（从状态0开始）
    res.init(1, 3);
    res.d[0][0] = -1; // 起始状态

    // 计算从状态0到状态2的最小路径
    res = res * seg[1]; // 注意相乘顺序
    // An * An-1 *  *   A2 * A1  矩阵相乘。 满足结合率

    // 输出结果
    if (res.d[0][2] >= 5 * n) {
      printf("-1\n"); // 无解
    } else {
      printf("%d\n", res.d[0][2]);
    }
  }

  return 0;
}